Первая программа "Hello, World!"
В этой главе мы создадим вашу первую полноценную программу на Rust, разберём её структуру и познакомимся с основными элементами синтаксиса языка. Традиционно первая программа выводит приветствие "Hello, World!" — и мы не будем нарушать эту традицию!
Создание проекта
Начнём с создания нового Rust-проекта с помощью Cargo:
# Создаём проект
cargo new hello_world
cd hello_world
# Просматриваем структуру
ls -la
Результат выполнения команд:
Created binary (application) `hello_world` package
hello_world/
├── Cargo.toml
├── src/
│ └── main.rs
└── .gitignore
- Cargo.toml — файл конфигурации проекта (манифест)
- src/main.rs — главный исходный файл программы
- .gitignore — настройки для системы контроля версий Git
Анализ структуры проекта
Файл Cargo.toml
Откройте файл Cargo.toml — это сердце любого Rust-проекта:
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
- Секция [package]
- Секция [dependencies]
- Дополнительные секции
Основная информация о проекте:
name— имя пакета (используется при публикации)version— версия в формате Semantic Versioningedition— версия языка Rust (2015, 2018, 2021)
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
authors = ["Ваше Имя <email@example.com>"]
description = "Моя первая программа на Rust"
license = "MIT"
Зависимости проекта:
Пока секция пустая, но позже здесь будут библиотеки:
[dependencies]
serde = "1.0"
tokio = { version = "1.0", features = ["full"] }
rand = "0.8"
Другие полезные секции:
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
# Основные зависимости
[dev-dependencies]
# Зависимости только для разработки и тестов
[build-dependencies]
# Зависимости для скриптов сборки
[[bin]]
name = "hello_world"
path = "src/main.rs"
Файл main.rs
Теперь откройте главный файл программы src/main.rs:
fn main() {
println!("Hello, world!");
}
Эта простая программа содержит все ключевые элементы Rust-приложения!
Разбор синтаксиса "Hello, World!"
Функция main
fn main() {
println!("Hello, world!");
}
//│ │ │ │ │
//│ │ │ │ └─ Закрывающая скобка функции
//│ │ │ └─ Содержимое функции (тело)
//│ │ └─ Открывающая скобка функции
//│ └─ Имя функции
//└─ Ключевое слово объявления функции
Особенности функции main:
🚀 Точка входа
main — это специальная функция, с которой начинается выполнение программы
📝 Синтаксис
fn — ключевое слово для объявления функций
🔧 Параметры
Пустые скобки () означают, что функция не принимает параметры
↩️ Возврат
Функция ничего не возвращает (тип () — unit type)
Макрос println!
println!("Hello, world!");
//│ │ │ │ │
//│ │ │ │ └─ Точка с запятой (завершение выражения)
//│ │ │ └─ Закрывающая кавычка строки
//│ │ └─ Строковый литерал
//│ └─ Открывающая скобка макроса
//└─ Восклицательный знак указывает на макрос
println! — это макрос, а не функция. Восклицательный знак ! после имени всегда указывает на макрос в Rust.
Возможности println!:
- Базовое использование
- Форматирование
- Отладочный вывод
fn main() {
println!("Hello, world!");
println!("Привет, мир!");
println!("Это вторая строка");
}
Вывод:
Hello, world!
Привет, мир!
Это вторая строка
fn main() {
let name = "Rust";
let year = 2010;
println!("Язык {} создан в {} году", name, year);
println!("Результат: {}", 2 + 3);
println!("Число в двоичном виде: {:b}", 42);
}
Вывод:
Язык Rust создан в 2010 году
Результат: 5
Число в двоичном виде: 101010
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
println!("Числа: {:?}", numbers);
println!("Подробно: {:#?}", numbers);
}
Вывод:
Числа: [1, 2, 3, 4, 5]
Подробно: [
1,
2,
3,
4,
5,
]
Запуск программы
Теперь запустим нашу программу несколькими способами:
Способ 1: Через Cargo (рекомендуется)
# Компиляция и запуск одной командой
cargo run
Что происходит под капотом:
Compiling hello_world v0.1.0 (/path/to/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 1.23s
Running `target/debug/hello_world`
Hello, world!
Способ 2: Компиляция и запуск отдельно
# Только компиляция
cargo build
# Запуск скомпилированного файла
./target/debug/hello_world
Способ 3: Через компилятор rustc
# Компиляция одного файла
rustc src/main.rs
# Запуск
./main
- cargo run — для разработки (удобно и быстро)
- cargo build — когда нужно только скомпилировать
- rustc — для простых однофайловых программ
Режимы сборки
Rust поддерживает разные режимы сборки проекта:
- Отладочная сборка
- Релизная сборка
Режим по умолчанию для разработки:
cargo build
# или
cargo run
Характеристики:
- Быстрая компиляция
- Большой размер файла
- Включена отладочная информация
- Медленное выполнение
- Файл:
target/debug/hello_world
Оптимизированная сборка для продакшена:
cargo build --release
# или
cargo run --release
Характеристики:
- Медленная компиляция
- Маленький размер файла
- Отключена отладочная информация
- Быстрое выполнение
- Файл:
target/release/hello_world
Сравнение производительности:
# Отладочная версия
time ./target/debug/hello_world
# Релизная версия
time ./target/release/hello_world
Модификация программы
Давайте улучшим нашу первую программу:
Версия 2: С переменными
fn main() {
let greeting = "Hello";
let target = "World";
println!("{}, {}!", greeting, target);
}
Версия 3: Интерактивная
use std::io;
fn main() {
println!("Как вас зовут?");
let mut name = String::new();
io::stdin()
.read_line(&mut name)
.expect("Не удалось прочитать строку");
println!("Привет, {}!", name.trim());
}
В интерактивной версии появились новые элементы:
use— импорт модулейlet mut— изменяемая переменнаяString::new()— создание строкиexpect()— обработка ошибок
Версия 4: С аргументами командной строки
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
println!("Привет, {}!", args[1]);
} else {
println!("Hello, World!");
println!("Использование: {} <имя>", args[0]);
}
}
Запуск:
cargo run Анна
# Вывод: Привет, Анна!
Структура файловой системы проекта
После компиляции структура проекта выглядит так:
hello_world/
├── Cargo.toml # Манифест проекта
├── Cargo.lock # Файл блокировки зависимостей (создаётся автоматически)
├── src/ # Исходный код
│ └── main.rs
├── target/ # Результаты компиляции
│ ├── debug/ # Отладочные сборки
│ │ ├── hello_world # Исполняемый файл
│ │ └── deps/ # Скомпилированные зависимости
│ └── release/ # Релизные сборки
│ └── hello_world
└── .gitignore
Папка target/ содержит временные файлы компиляции и может быть удалена в любой момент. Cargo пересоздаст её при следующей сборке.
Полезные команды Cargo
Теперь, когда у нас есть рабочий проект, познакомимся с основными командами:
| Команда | Описание | Пример |
|---|---|---|
cargo new | Создать новый проект | cargo new my_app |
cargo build | Скомпилировать проект | cargo build --release |
cargo run | Скомпилировать и запустить | cargo run -- arg1 arg2 |
cargo check | Проверить код без компиляции | cargo check |
cargo clean | Очистить папку target/ | cargo clean |
cargo test | Запустить тесты | cargo test |
cargo doc | Сгенерировать документацию | cargo doc --open |
Практические примеры
# Быстрая проверка синтаксиса (без создания исполняемого файла)
cargo check
# Подробный вывод процесса компиляции
cargo build --verbose
# Очистка и пересборка проекта
cargo clean && cargo build
# Запуск с аргументами
cargo run -- --help
# Просмотр информации о проекте
cargo metadata --no-deps --format-version 1
Распространённые ошибки и их исправление
Ошибка 1: Забыта точка с запятой
fn main() {
println!("Hello, world!") // Отсутствует ;
}
Ошибка компилятора:
error: expected `;`, found `}`
✅ Правильно:
fn main() {
println!("Hello, world!"); // Добавлена ;
}
Ошибка 2: Неправильный синтаксис функции
function main() { // Использовано 'function' вместо 'fn'
println!("Hello, world!");
}
✅ Правильно:
fn main() { // Используется 'fn'
println!("Hello, world!");
}
Ошибка 3: Неправильное использование кавычек
fn main() {
println!('Hello, world!'); // Одинарные кавычки для строки
}
✅ Правильно:
fn main() {
println!("Hello, world!"); // Двойные кавычки для строки
}
Одинарные кавычки ' в Rust используются только для символов (char), а двойные кавычки " — для строк (string literals).
Понимание процесса компиляции
Что происходит при выполнении cargo run
- Чтение Cargo.toml — Cargo анализирует конфигурацию проекта
- Разрешение зависимостей — загружаются и компилируются библиотеки
- Компиляция исходного кода — rustc преобразует Rust-код в машинный код
- Линковка — создаётся финальный исполняемый файл
- Запуск — выполняется скомпилированная программа
Промежуточные файлы
# Посмотрим, что создал компилятор
find target/debug -name "*hello*" -type f
# Информация о скомпилированном файле
file target/debug/hello_world
size target/debug/hello_world
Заключение
В этой главе мы:
✅ Создали первый Rust-проект с помощью Cargo ✅ Разобрали структуру простой программы ✅ Изучили синтаксис функции main и макроса println! ✅ Научились компилировать и запускать программы ✅ Познакомились с базовыми командами Cargo ✅ Рассмотрели типичные ошибки и их исправление
Теперь вы понимаете базовую структуру Rust-программы и готовы к изучению более сложных концепций языка!
В следующей главе: "Знакомство с системой сборки Cargo" — мы углубимся в возможности Cargo, научимся работать с зависимостями и настраивать проекты.
Практические задания
- Создайте программу, которая выводит ваше имя и возраст
- Модифицируйте программу для вывода таблицы умножения на 5
- Создайте программу, которая принимает два аргумента командной строки и выводит их в обратном порядке
Вопросы для самопроверки
- Чем отличается макрос от функции в Rust?
- Что произойдёт, если удалить восклицательный знак из
println!? - В чём разница между debug и release сборкой?
- Какие файлы создаёт команда
cargo new?